As computers and the computer software that runs on such computers increase in performance and complexity, the development of computer software becomes increasingly expensive, difficult and time consuming. One predominant manner of combating the difficulties of software development is through increased reliance on pre-existing code. Object-oriented software design is premised in large part on the concept of code reuse, where software is compartmentalized into objects that are individually created, tested and refined, and where more complex objects are built by assembling together simpler objects to leverage the prior efforts of others, and avoiding the need to develop new software entirely from scratch.
The software executing on a computer is often highly layered, with program code resident in one layer relying on the services of program code resident in lower layers. As an example, a computer application may rely on one or more libraries of commonly-used functions, which themselves often rely on an underlying operating system to provide lower level services to the application and/or the libraries. Likewise, an operating system may rely on drivers to facilitate the management, control and access to various hardware resources in a computer, as well as extremely low level kernel and BIOS code to support the fundamental memory and task management duties for the computer.
To facilitate the reuse of code in a given software layer, it is often necessary for the software layer to provide a consistent interface to program code that may be resident in higher layers. An interface typically refers to the names or identities of the functions that are accessible in a given layer of software, as well as the expected inputs and outputs for those functions. As a result, even if the underlying code is updated, extended or otherwise modified, so long as the same interface is maintained in a given layer of code, higher layers of code that access that layer of code will often still be able to access the functions in that layer of code with little or no modification.
Another manner in which software reuse can be leveraged is through the adaptation of the same software on different types of computers. Software is often written, for example, in a relatively system-agnostic and human readable source code format, and then compiled by a compiler into a system-specific and machine readable object code format. In many instances, if compilers exist for multiple types of computers, the same source code can be compiled by different compilers into system-specific object code for execution on those different types of computers. Further, in many instances such compilation can occur with little or no customization of the source code for a particular computer type.
Still another manner of leveraging software reuse is through the use of virtual software machines such as supported by the Java programming language developed by Sun Microsystems. Rather than being compiled for a particular type of computer, Java programs are typically compiled into an intermediate format that is system-independent. Java virtual machines, specifically developed for and resident on different types of computers, then interpret or further compile the intermediate format versions of Java programs to permit the same intermediate format version of a Java program to run without modification on the various different types of computers.
Software that is intended to be compiled, interpreted or otherwise configured to execute on different types of computers often takes the form of a standardized code base. In many instances, however, and despite efforts to implement a code base as generically as possible, substantial modifications may nonetheless be required to specifically adapt a standardized code base to operate accurately and efficiently on a particular type of computer. Particularly when the standardized code base is adapted for a particular type of computer by an entity other than that which developed the original standardized code base, substantial efforts may be required on the part of that other entity.
As an example, the Java programming language supports a number of libraries that often must be specifically adapted for use on different types of computers. The Java Abstract Window Toolkit (AWT), for example, is a library package that provides a number of graphical user interface capabilities for Java programs, such as the creation and manipulation of windows, menus, buttons, etc. The Java AWT package is generically designed to run on a single-user computer, whereby the display of graphical user interface components occurs on the same computer upon which a Java program is executing. In some computer environments, e.g., in client/server computer environments, the display of graphical user interface components may occur on a different computer than that upon which a Java program is executing. As a result, in such environments, the Java AWT package must be adapted to operate in a distributed manner, so that requests in a program running on one computer to perform such operations as creating or updating windows, buttons, etc., are forwarded over a network to another computer for display.
While such adaptation can be costly and time consuming, it can be manageable if the underlying standard code base remains constant. For example, automated tools may be usable in some instances to adapt certain portions of a code base for a particular target platform. Of note, however, it has been found that such automated tools are often limited in capabilities, and some degree of manual adaptation is almost always required.
However, if the standard code base is updated or revised from time to time, the specialized adaptations of the code base will likewise need to be updated for compatibility with the updates to the standard code base. Reproducing such adaptations, however, has traditionally required manually reapplying the same changes made to an earlier version of a standardized code base to the later version of the same. Over time, repeated updates to a standardized code base can place significant support burdens on the entities that maintain the specialized adaptations of that code base. To the extent that the adaptation of a standard code base could be automated, the burdens associated with performing such adaptations could be dramatically reduced. As such, a need exists in the art for a manner of automating the adaptation of standard code bases to specialized adaptations thereof.
In some programming environments, system-dependent changes in source code may be accounted for using “conditional compilation” constructs. With such constructs, sections of system-specific code for multiple systems can be incorporated into the same source code, with compiler commands used to filter out unneeded code during compilation for a particular target platform.
Using conditional compilation, system-specific changes to a shared or standard code base can be safely saved directly in that code base, without affecting other system-specific changes, given that irrelevant system-specific changes will effectively be filtered out during compilation for a particular platform. Moreover, by using conditional compilation, system-specific changes made in a code base can often be made available in subsequent releases of that code base with little additional effort.
In some programming environments, however, conditional compilation is not supported. As a result, system-specific changes often cannot be saved back in the standard code base, and every iteration of the development cycle (for system-specific changes) must effectively start from scratch, with many if not all of the same adaptations made to the prior version of the code base having to be manually applied to the new version of the same. Even where automated tools are used to automatically adapt portions of a code base for use on a particular target platform, the remaining manual adaptations that are practically always required still must be applied.
It has been found, however, that such manual changes can be difficult to reconstruct, particularly given the realities of the business world, where programmers may come and go, and where code documentation may not be as comprehensive as it should be. Reproducing some of the changes made to a prior version of an adapted code base into a new version of the adapted code base may therefore require substantial study of the previous version of the adapted code base, as well as additional testing to ensure that all adaptations have been properly incorporated.
In addition, certain software version control environments support the ability to maintain multiple versions of software through storage of only the differences between versions. Such environments, however, typically rely on a rudimentary line-by-line analysis of software versions, so that different versions of software can be recreated simply by reapplying difference information to prior versions of the software. However, line-by-line analysis cannot distinguish between semantic differences (i.e., differences that alter the program structure or operation) and non-semantic differences. As a result, even irrelevant changes such as the ordering of methods or classes, changes in comments, and/or the addition or elimination of line breaks, will be identified by line-by-line analysis, often rendering such analysis useless for identifying semantic changes made to a version of software.
A significant need therefore exists in the art for a manner of facilitating the adaptation of a standard code base, and in particular, to reduce the degree of manual intervention required to adapt updated versions of a standard code base.